// Kony

#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "UObject/Interface.h"
#include "AbilitySystem/Data/CharacterClassInfo.h"
#include "CombatInterface.generated.h"

class UNiagaraSystem;
class UAnimMontage;
class UAbilitySystemComponent;


//用于能力系统组件注册委托，用于能力系统组件存在时 广播，这样一些例如 NiagaraComponent 组件需要使用ASC但是开始不存在，需要动态获取的时候
DECLARE_MULTICAST_DELEGATE_OneParam(FOnASCRegistered, UAbilitySystemComponent*);
//用于广播角色死亡动态多播广播，用于广播角色死亡，蓝图可接收角色死亡处理后续清除操作
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnDeathSignature, AActor*, DeadActor);
//多播广播 受到的伤害值
DECLARE_MULTICAST_DELEGATE_OneParam(FOnDamageSignature,float /*DamageAmount*/)

//设置蒙太奇攻击动画选择器，用于在攻击蓝图中选择蒙太奇攻击动画
USTRUCT(BlueprintType)
struct FTaggedMontage
{
	GENERATED_BODY()
	//蒙太奇攻击动画
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	class UAnimMontage* Montage = nullptr;
	//蒙太奇游戏标签，用于通过游戏标签播放蒙太奇攻击动画 可单一播放或连击，并在gameplay cue提示中可以通过 蒙太奇攻击标签来区分当前攻击
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	FGameplayTag MontageTag;
	//战斗插槽游戏标签，这个是用于找到对应的攻击动画获取武器插槽位置
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	FGameplayTag SocketTag;
	//攻击打击音效声音（这是打中物体的音效，挥动音效是在动画里广播插槽做的）
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	USoundBase* ImpactSound = nullptr;
	
};

//战斗接口
// This class does not need to be modified.
UINTERFACE(MinimalAPI, BlueprintType)
class UCombatInterface : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class GASC_HUANLING_API ICombatInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	//获取ASC能力系统组件注册委托（增加=0 是为了作为纯虚函数，这样任何继承这个的类都要重写）
	virtual FOnASCRegistered& GetOnASCRegisteredDelegate() = 0;
	//角色死亡委托，用于通知一些无法获取到角色死亡的组件
	virtual FOnDeathSignature& GetOnDeathDelegate() = 0;
	//受到伤害广播函数
	virtual FOnDamageSignature& GetOnDamageSignature() = 0;
	//获取玩家等级
	UFUNCTION(BlueprintNativeEvent)
	int32 GetPlayerLevel();
	//返回武器插槽的位置 用于绑定游戏技能发射位置,可根据MontageTag区别插槽位置
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	FVector GetCombatSocketLocation(const FGameplayTag& SocketTag, bool bUseFacing = false, float FacingDistance = 150.0f);
	//更改面向目标
	UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
	void UpdateFacingTarget(const FVector& Target);

	//返回对应角色的受击动画
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	UAnimMontage* GetHitReactMontage();
	//角色是否死亡
	virtual void Die(const FVector& DeathImpulse) = 0;
	//获取角色是否死亡
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	bool IsDead() const;
	//获取化身Actor
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	AActor* GetAvatar();
	
	//设置怪物攻击目标
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	void SetCombatTarget(AActor* InCombatTarget);
	//获取怪物攻击目标
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	AActor* GetCombatTarget() const;
	//获取蒙太奇攻击动画数组函数
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	TArray<FTaggedMontage> GetAttackMontages();
	//受击出血效果
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	UNiagaraSystem* GetHitBloodEffect();
	//通过标签TAG返回TaggedMontage结构体
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	FTaggedMontage GetTaggedMontageByTag(const FGameplayTag& MontageTag);
	//获取当前召唤随从数量
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	int32 GetMinionCount();
	//递增写入当前召唤随从数量
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	void IncremenetMinionCount(int32 Amount);
	//获取怪物职业
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	ECharacterClass GetCharacterClass();
	//设置持续施法
	UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
	void SetInSustainedRelease(bool bInLoop);

	//重写获取插槽组件函数,用于获取武器插槽等 角色身上的插槽
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	USkeletalMeshComponent* GetSocketComponent(const FString& SocketName);

	//显示目标锁定光圈
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	void ShowTargetIndicator();
	//隐藏目标锁定光圈
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	void HideTargetIndicator();

	//是否正在持续被电击
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	bool IsBeingShocked() const;
	//设置持续被电击
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	void SetIsBeingShocked(bool bInShock);
};
